/*
 * =====================================================================================
 *
 *       Filename:  netBuffer.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  07/13/2012 02:56:47 PM
 *       Revision:  none
 *       Compiler:  gcc/g++
 *
 *         Author:  wangtengchao , wangtengchao AT gmail.com
 *   Organization:  
 *
 * =====================================================================================
 */

#include"netBuffer.h"
#include<sys/uio.h>
#include<iostream>
using namespace std;
using namespace inm::net;


//ssize_t---signed size_t    size_t--unsigned int
ssize_t NetBuffer::readFromFd(int fd)
{//try best to read more by using extraBuf 
	char extraBuf[65536] = {'\0'};//cannot use push_back to increase size of buffer_  .i think address may change
    ssize_t writeable_num = _writeableNum();//save for mergeBuffer
	struct iovec iov[2];
	iov[0].iov_base = _writeBegin(); // 
	iov[0].iov_len = writeable_num;	
	iov[1].iov_base = extraBuf;
	iov[1].iov_len = sizeof(extraBuf);
    ssize_t readNum = readv(fd,iov,2);

	if(readNum == -1)
		return -1;//error
	if(readNum <= writeable_num)
	{//all only write into buffer_
		writeIndex_ += readNum;
	}
	else
	{// readNum > writeableNum  some write into buffer_   some write into ertraBuf
        writeIndex_	= buffer_.size();
		_expandAndWrite(extraBuf,readNum-writeable_num);	
	}
	return readNum;	
}
void NetBuffer::shrink()
{
	std::vector<char>(buffer_).swap(buffer_);
}
void NetBuffer::_expandAndWrite(const char* data,size_t num)
{

    if((readIndex_-InitialPrependSize + buffer_.size()-writeIndex_) >= num)
	{//should move the readable block to the front and don't need expand
		_moveToFront();
		std::copy(data,&data[num],_writeBegin());//num !not num-1 because copy  [first,end)
	}	
    else//free space is not enough .insert into the back immediately
        buffer_.insert(buffer_.begin()+writeIndex_,data,&data[num]);
	writeIndex_ += num;

}

void NetBuffer::append(const char* data,size_t num)
{
	size_t writeable_num = _writeableNum();
	if(num <= writeable_num)	
	{
		std::copy(data,&data[num],_writeBegin());	
		writeIndex_ += num;//don't forget
	}
	else
	{//num > writeable_num
        std::copy(data,&data[writeable_num],_writeBegin());//some write to the original buffer
		writeIndex_  = buffer_.size();
        _expandAndWrite(&data[writeable_num],num-writeable_num);//some write to the expand buffer
	}
}



void NetBuffer::_moveToFront()
{
#ifdef NET_DEBUG 
    cout<<"movetofront"<<endl;
#endif
    std::copy(buffer_.begin()+readIndex_,buffer_.begin()+writeIndex_,_beginWithoutHead());
    writeIndex_ -= (readIndex_ -InitialPrependSize);
    readIndex_= InitialPrependSize;
}
int NetBuffer::prepend(const void *data, size_t len)
{//return the write length   -1 means error
    if(len > _prependable())
        return -1;
    else
    {
        const char* _data  = static_cast<const char*>(data);
        readIndex_ -= len;
        std::copy(_data,&_data[len],buffer_.begin()+readIndex_);
    }
    return len;

}

